<?php

namespace backend\controllers;


use backend\models\PermissionForm;
use Yii;
use yii\data\ArrayDataProvider;
use yii\filters\VerbFilter;
use yii\rbac\Permission;
use yii\web\NotFoundHttpException;

class PermissionController extends BaseController
{
    /**
     * @return array
     */
    public function behaviors()
    {
        return array_merge(parent::behaviors(),
            [
                'verbs' => [
                    'class' => VerbFilter::className(),
                    'actions' => [
                        'delete' => ['post'],
                        'save' => ['post'],
                    ],
                ],
            ]);
    }

    /**
     * @param null $name
     * @return string|\yii\web\Response
     */
    public function actionIndex($name = null)
    {
        $authManager = Yii::$app->getAuthManager();
        $permissions = $authManager->getPermissions();
        $roles = $authManager->getRoles();
        if ($name !== null) {
            foreach ($roles as $role) {
                if ($role->name === $name) {
                    $roles = [$role];
                    break;
                }
            }
        }

        $roleChildrenList = [];
        foreach ($roles as $role) {
            $roleChildrenList[$role->name] = $authManager->getChildren($role->name);
        }

        $permissionChildren = [];
        foreach ($permissions as &$permission) {
            $permission = (array)$permission;
            $permission['roles'] = [];

            if (preg_match('#^[A-z0-9\-_]+:$#', $permission['name'])) {
                $permission['is_valid'] = false;
            } else {
                $permission['is_valid'] = true;
            }

            foreach ($roleChildrenList as $roleName => $children) {
                foreach ($children as $child) {
                    if ($child->name === $permission['name']) {
                        $permission['roles'][] = $roleName;
                    }
                }
            }

            if ($pos = strrpos($permission['name'], '/')) {
                $parent = substr($permission['name'], 0, $pos);
                $permission['parent'] = $parent;
                $permissionChildren[$parent][] = $permission;
            } else {
                $permission['parent'] = 0;
                $permissionChildren[0][] = $permission;
            }
        }

        foreach ($permissionChildren as &$children) {
            foreach ($children as &$child) {
                if (isset($permissionChildren[$child['name']])) {
                    $child['is_parent'] = true;
                } else {
                    $child['is_parent'] = false;
                }
            }
        }

        return $this->render('index', array(
            'roles' => $roles,
            'dataProvider' => new ArrayDataProvider(['models' => $this->generateTree($permissionChildren)]),
        ));
    }

    /**
     * 保存权限
     *
     * @return \yii\web\Response
     */
    public function actionSave()
    {
        if (isset($_POST['permission'])) {
            $newPermissionList = (array) $_POST['permission'];
            $authManager = Yii::$app->authManager;
            $roles = $authManager->getRoles();
            $permissions = $authManager->getPermissions();

            $oldPermissionList = [];
            foreach ($roles as $name => $role) {
                if (isset($newPermissionList[$name])) {
                    foreach ($authManager->getChildren($role->name) as $permission) {
                        $oldPermissionList[$role->name][] = $permission->name;
                    }
                }
            }
            $addPermissionList = [];
            $delPermissionList = [];

            foreach ($newPermissionList as $roleName => $permissionList) {
                foreach ($permissionList as $i => $name) {
                    if (preg_match('#^[A-z0-9\-\_]+:$#', $name)) {
                        unset($permissionList[$i]);
                    }
                }
                $permissionList = is_array($permissionList) ? $permissionList : [];
                $_oldPermissionList = isset($oldPermissionList[$roleName]) ? $oldPermissionList[$roleName] : [];
                $addPermissionList[$roleName] = array_diff($permissionList , $_oldPermissionList);
                $delPermissionList[$roleName] = array_diff($_oldPermissionList , $permissionList);
            }

            foreach ($addPermissionList as $roleName => $permissionNames) {
                foreach ($permissionNames as $permissionName) {
                    if (isset($roles[$roleName]) && isset($permissions[$permissionName])) {
                        $authManager->addChild($roles[$roleName], $permissions[$permissionName]);
                    }
                }
            }

            foreach ($delPermissionList as $roleName => $permissionNames) {
                foreach ($permissionNames as $permissionName) {
                    if (isset($roles[$roleName]) && isset($permissions[$permissionName])) {
                        $authManager->removeChild($roles[$roleName], $permissions[$permissionName]);
                    }
                }
            }

            Yii::$app->session->setFlash('success', '权限保存成功。');
        }
        return $this->redirect(['index']);
    }

    /**
     * 生成权系树
     *
     * @param $children
     * @param int $parent
     * @param null $maxDepth
     * @return array
     */
    protected function generateTree($children, $parent = 0, $maxDepth = null)
    {
        if ($maxDepth === null) {
            $maxDepth = count($children);
        }

        $processParents = array();
        $tree = array();

        $processParents[] = $parent;
        while (count($processParents)) {
            $parent = array_pop($processParents);
            $depth = count($processParents);

            if ($maxDepth > $depth && !empty($children[$parent])) {
                $hasChildren = false;
                $child = current($children[$parent]);

                do {
                    if (empty($child)) {
                        break;
                    }

                    $child['depth'] = $depth;
                    $tree[] = $child;

                    if (!empty($children[$child['name']])) {
                        $hasChildren = true;
                        $processParents[] = $parent;
                        $processParents[] = $child['name'];
                        reset($children[$child['name']]);
                        next($children[$parent]);
                        break;
                    }
                } while ($child = next($children[$parent]));

                if (!$hasChildren) {
                    reset($children[$parent]);
                }
            }
        }

        return $tree;
    }

    /**
     * @return string|\yii\web\Response
     */
    public function actionCreate()
    {
        $model = new PermissionForm();
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            Yii::$app->session->setFlash('success', '权限创建成功。');
            return $this->redirect(['index']);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }

    /**
     * @param $name
     * @return string|\yii\web\Response
     */
    public function actionUpdate($name)
    {
        $model = new PermissionForm($this->loadModel($name));
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            Yii::$app->session->setFlash('success', '权限更新成功。');
            return $this->redirect(['index']);
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }

    /**
     * @param $name
     * @return \yii\web\Response
     */
    public function actionDelete($name)
    {
        $permission = $this->loadModel($name);
        Yii::$app->authManager->remove($permission)
        &&
        Yii::$app->session->setFlash('success', '权限删除成功。');
        return $this->redirect(['index']);
    }

    /**
     * @param $name
     * @return Permission
     * @throws \yii\web\NotFoundHttpException
     */
    public function loadModel($name)
    {
        $authManager = Yii::$app->getAuthManager();
        if (!$permission = $authManager->getPermission($name)) {
            throw new NotFoundHttpException('The requested page does not exist.');
        } else {
            return $permission;
        }
    }
} 